package org.imraniqbal.engine;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.LinkedList;

/**
 * Contains all saved states of the game for undo and redo
 * functionality
 * @author imran
 *
 */
public class Memory <T extends Game> {

	private final static int MEM_SIZE = 6;
	private LinkedList<ByteArrayOutputStream> memArray;
	private int position;
	
	public Memory(){
		memArray = new LinkedList<ByteArrayOutputStream>();
		position = 0;
	}
	
	private boolean isFull(){
		return (memArray.size() > MEM_SIZE);
	}
	/**
	 * Generic function in case something wants to know if nothing is in the Memory
	 * @return true if empty, false otherwise
	 */
	public boolean isEmpty(){
		return (memArray.size() == 0);
	}
	/**
	 * Saves the state of a game that you pass it so that you may undo and/or redo later
	 * @param game the game that you want to save
	 * @throws IOException
	 */
	public void addGameState(Game game) throws IOException{
		ByteArrayOutputStream state = new ByteArrayOutputStream();
		game.serialize(state);
		position = 0;
		memArray.addFirst(state);
		if(isFull()){ memArray.removeLast(); }
	}
	@SuppressWarnings("unchecked")
	private T getGameState(int index) throws IOException, ClassNotFoundException{
		if( isEmpty()) { return null; }
		ByteArrayInputStream input = new ByteArrayInputStream(memArray.get(index).toByteArray());
		ObjectInputStream is = new ObjectInputStream(input);
		T game = (T)is.readObject();
		is.close();
		return game;
	}
	/**
	 * @return Will return a game that is one move behind the current game
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public T undo() throws IOException, ClassNotFoundException{
		if(position + 1 > MEM_SIZE){
			return null;
		}
		position++;
		return getGameState(position);
	}
	/**
	 * @return If an undo was used, this returns a game that is one step ahead of the undo
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public T redo() throws IOException, ClassNotFoundException{
		if(position -1 < 0){
			return null;
		}
		position--;
		return getGameState(position);
	}
	
}
